﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Net;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ServiceModel.Syndication;
using System.Xml;

namespace Nwsfeed
{

    public delegate void OfflineModeActivatedEventHandler(object sender, EventArgs e);
    public delegate void OnlineModeActivatedEventHandler(object sender, EventArgs e);

    public sealed class NwsfeedApp : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event CollectionChangeEventHandler CollectionChanged;
        public event OfflineModeActivatedEventHandler OfflineModeActivated;
        public event OnlineModeActivatedEventHandler OnlineModeActivated;

        // Preferences

        private double titleFontSize;
        private double bodyFontSize;

        public double TitleFontSize { get { return titleFontSize; } set { titleFontSize = value; OnPropertyChanged("TitleFontSize"); } }
        public double BodyFontSize { get { return bodyFontSize; } set { bodyFontSize = value; OnPropertyChanged("BodyFontSize"); } }

        //

        public static String WorkingDirectory { get; private set; }
        private RSSFeed lastSelected;
        public RSSFeed LastSelected { get { return lastSelected; } set { lastSelected = value; OnPropertyChanged("LastSelected"); } }

        private bool offlineMode;
        public bool OfflineMode { get { return offlineMode; } private set { offlineMode = value; OnOfflineModePropertyChanged(); } }

        private void OnOfflineModePropertyChanged()
        {
            if (OfflineMode && OfflineModeActivated != null)
                OfflineModeActivated(this, new EventArgs());
            else if (OnlineModeActivated != null)                
                OnlineModeActivated(this, new EventArgs());
        }

        private ObservableCollection<RSSFeed> feeds;
        public ObservableCollection<RSSFeed> Feeds
        {
            get { return feeds; }
            set { feeds = value; OnPropertyChanged("Feeds"); }
        }

        public NwsfeedApp()
        {
            LastSelected = new RSSFeed();
            WebHelper.NetworkChanged += new EventHandler<NetworkChangedEventArgs>(WebHelper_NetworkChanged);
            feeds = new ObservableCollection<RSSFeed>();
        }

        void WebHelper_NetworkChanged(object sender, NetworkChangedEventArgs e)
        {
            if (OfflineMode && WebHelper.IsNetworkAvailable)
                OfflineMode = false;

            if (!OfflineMode && !WebHelper.IsNetworkAvailable)
                OfflineMode = true;
        }

        public bool SwitchToOfflineMode()
        {
            OfflineMode = true;
            return true;
        }

        public bool SwitchToOnlineMode()
        {
            if (WebHelper.IsNetworkAvailable)
            {
                OfflineMode = false;
                return true;
            }
            else 
            {
                offlineMode = true;
                return false;
            }
        }

        public void Initialize()
        {
            WebHelper.StartNetworkObservation();

            WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
            Directory.CreateDirectory(WorkingDirectory + "profile\\");
            Directory.CreateDirectory(WorkingDirectory + "cache\\");

            TitleFontSize = 28.0f;
            BodyFontSize = 14.0f;
        }

        public void LoadProfileSettings()
        {
            // TO DO: load from cache
            // if in online mode, update the feeds (async)

            if (!OfflineMode)
            {
                String lastSelectedUri = null;
                List<String> feedUris = new List<string>();
                try
                {
                    using (Stream stream = File.Open(WorkingDirectory + "profile\\profile.xml", FileMode.Open))
                    using (XmlReader reader = XmlReader.Create(stream))
                    {
                        while (reader.Read())
                        {
                            if (reader.IsStartElement())
                            {
                                switch (reader.Name)
                                {
                                    case "LastSelected":
                                        {
                                            lastSelectedUri = reader.ReadElementString("LastSelected");
                                            break;
                                        }
                                    case "TitleFontSize":
                                        {
                                            TitleFontSize = Double.Parse(reader.ReadElementString("TitleFontSize"));
                                            break;
                                        }
                                    case "BodyFontSize":
                                        {
                                            BodyFontSize = Double.Parse(reader.ReadElementString("BodyFontSize"));
                                            break;
                                        }
                                    case "Feed":
                                        {
                                            RSSFeed feed = new RSSFeed();
                                            String attribute = reader["Uri"];
                                            if (attribute != null)
                                                feed.Uri = attribute;
                                            attribute = reader["Title"];
                                            if (attribute != null)
                                                feed.Title = attribute;

                                            attribute = reader["Image"];
                                            if (attribute != null)
                                            {
                                                if (File.Exists(attribute))
                                                    feed.ImageCacheUri = attribute;
                                            }

                                            AddFeed(feed);
                                            break;
                                        }
                                }
                            }
                        }
                    }
                    LastSelected = feeds.First(i => i.Uri == lastSelectedUri);

                }
                catch
                {
                    // no file found
                    return;
                }
            }
        }

        public void SaveProfileSettings()
        {
            try
            {
                using (Stream stream = File.Open(WorkingDirectory + "\\profile\\profile.xml", FileMode.Create))
                using (XmlWriter writer = XmlWriter.Create(stream))
                {
                    writer.WriteStartDocument();
                    writer.WriteStartElement("Profile");
                    writer.WriteElementString("TitleFontSize", ((int)TitleFontSize).ToString());
                    writer.WriteElementString("BodyFontSize", ((int)BodyFontSize).ToString());
                    writer.WriteElementString("LastSelected", LastSelected.Uri);

                    writer.WriteStartElement("Feeds");

                    foreach (RSSFeed feed in Feeds)
                    {
                        writer.WriteStartElement("Feed");
                        writer.WriteAttributeString("Uri", feed.Uri);
                        writer.WriteAttributeString("Title", feed.Title);
                        writer.WriteAttributeString("Image", feed.ImageCacheUri);
                        writer.WriteEndElement();
                    }

                    writer.WriteEndElement();
                    writer.WriteEndElement();
                    writer.WriteEndDocument();
                }
            }
            catch 
            {
                // unable to save settings
            }
        }

        public void RemoveFeed(RSSFeed feed)
        {
            Feeds.Remove(feed);
            SaveProfileSettings();
        }

        public void AddFeed(RSSFeed feed)
        {
            if (!AllreadySubscribedTo(feed))
            {
                Feeds.Add(feed);
                SaveProfileSettings();
            }
        }

        public bool AllreadySubscribedTo(RSSFeed feed)
        {
            foreach (RSSFeed subscribedFeed in feeds)
                if (feed.Uri == subscribedFeed.Uri)
                    return true;
            return false;
        }

        private void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

        protected void OnCollectionChanged(RSSFeed feed)
        {
            CollectionChangeEventHandler handler = CollectionChanged;
            if (handler != null)
            {
                handler(this, new CollectionChangeEventArgs(CollectionChangeAction.Add, feed));
            }
        }
    }
}
